package com.yswy.common.utils;


import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Description 华为对象存储工具类
 **/
@Service
@Slf4j
public class HuaWeiYunOBSUtil {


    @Value(value = "${huaweiyun-obs.endpoint}")
    public String endpoint;
    @Value(value = "${huaweiyun-obs.accessUrl}")
    public String accessUrl;
    @Value(value = "${huaweiyun-obs.ak}")
    public String ak;
    @Value(value = "${huaweiyun-obs.sk}")
    public String sk;
    @Value(value = "${huaweiyun-obs.bucketname}")
    public String bucketname;

    public String getEndpoint() {
        return endpoint;
    }

    public String getAccessUrl() {
        return accessUrl;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getAk() {
        return ak;
    }

    public void setAk(String ak) {
        this.ak = ak;
    }

    public String getSk() {
        return sk;
    }

    public void setSk(String sk) {
        this.sk = sk;
    }

    public String getBucketname() {
        return bucketname;
    }

    public void setBucketname(String bucketname) {
        this.bucketname = bucketname;
    }

    /**
     * 获取指定路径下的ObsObject
     *
     * @param filePath 需要检索的文件夹路径
     * @return 路径下的所有的ObsObject，包括子文件夹下的ObsObject
     */
    public List<ObsObject> getFolderObjects(String filePath) {
        List<ObsObject> list = new ArrayList<>();
        ListObjectsRequest request = new ListObjectsRequest(bucketname);
        if (filePath != null && (!"".equals(filePath.trim()))) {
            request.setPrefix(filePath);
        }
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);

        request.setMaxKeys(100);
        ObjectListing result;
        do {
            result = obsClient.listObjects(request);
            for (ObsObject obsObject : result.getObjects()) {
                list.add(obsObject);
            }
            request.setMarker(result.getNextMarker());
        } while (result.isTruncated());
        return list;
    }

    public String toUrl(MultipartFile file , String fileUrl) {
        if (null != file) {
            try {
                // https://basckstatl.obs.cn-north-1.myhuaweicloud.com/flashSale/20.png
                String originalFilename = file.getOriginalFilename();
                originalFilename = com.yswy.common.utils.StringUtils.isNotEmpty(originalFilename) ? originalFilename.replaceAll("(.*)\\.", "") : "";
                return asyncUpload(String.format(fileUrl+"/%s.%s", UUID.randomUUID(), originalFilename), file.getInputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    /**
     * 上传
     *
     * @param fileName 上传的文件
     * @param fileHost bucket下文件夹的路径，不能用\或/开头和结尾
     * @param in       文件输入流
     * @return fileUrl 文件的url(bucket的路径）
     */
    public PutObjectResult upload(String fileName, String fileHost, InputStream in) {
//        log.info("=========>OSS文件上传开始:fileName:{}:fileHost:{}", fileName, fileHost);
        if (null == in) {
            return null;
        }
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//        String dateStr = format.format(new Date());
//        String fileUrl = fileHost + "/" + (dateStr + "/" + UUID.randomUUID().toString().replace("-", "") + "-" + fileName);
        String fileUrl = fileHost + "/" + fileName;
//        log.info("fileUrl:" + fileUrl);
        //生成obsClient
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);
        PutObjectResult putObjectResult = null;
        try {
            putObjectResult = obsClient.putObject(bucketname, fileUrl, in);//wgzsFiles/2019-07-25/dsdsahuihfisahifsa-file
            if (null != putObjectResult) {
//                log.info("==========>OBS文件上传成功,OBS地址：" + putObjectResult.getObjectUrl());
                return putObjectResult;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 异步上传
     *
     * @param fileUrl 上传的文件路径
     * @param in       文件输入流
     * @return fileUrl 文件的url(bucket的路径）
     */
    @Async
    public String asyncUpload(String fileUrl, InputStream in) {
        String url = "";
        log.info("=========>OBS文件上传开始:fileUrl:{}", fileUrl);
        if (null == in) {
            return url;
        }
        //生成obsClient
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);
        PutObjectResult putObjectResult = null;
        try {
            putObjectResult = obsClient.putObject(bucketname, fileUrl, in);
            if (null != putObjectResult) {
                log.info("==========>OBS文件上传成功,OBS地址：" + putObjectResult.getObjectUrl());
                url = putObjectResult.getObjectUrl();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return url;
    }



    /**
     * 使用临时ak sk token上传
     * @Author baoruizhe
     * @Date 20:57 2020/8/10
     * @Param [fileName, fileHost, in]
     * @return java.lang.String
     **/
    public String temporaryUpload(String ak, String sk,String token, String fileName, String fileHost, InputStream in) {
        log.info("=========>OSS文件上传开始:fileName:{}:fileHost:{}", fileName, fileHost);
        if (null == in) {
            return null;
        }
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//        String dateStr = format.format(new Date());
//        String fileUrl = fileHost + "/" + (dateStr + "/" + UUID.randomUUID().toString().replace("-", "") + "-" + fileName);
        String fileUrl = fileHost + "/" + fileName;
        log.info("fileUrl:" + fileUrl);
        //生成obsClient
        ObsClient obsClient = new ObsClient(ak, sk,token, endpoint);
        PutObjectResult putObjectResult = null;
        try {
            putObjectResult = obsClient.putObject(bucketname, fileUrl, in);//wgzsFiles/2019-07-25/dsdsahuihfisahifsa-file
            if (null != putObjectResult) {
                log.info("==========>OBS文件上传成功,OBS地址：" + putObjectResult.getObjectUrl());
                return putObjectResult.getObjectUrl();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 超过100M建议用以此方法 分段上传
     * @Author baoruizhe
     * @Date 20:57 2020/8/10
     * @Param [fileName, fileHost, largeFile]
     * @return java.lang.String
     **/
    public String largeUpload(String fileName, String fileHost, File largeFile) {

        String fileUrl = fileHost + "/" + fileName;
        // 创建ObsClient实例
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);

        // 初始化线程池
        ExecutorService executorService = Executors.newFixedThreadPool(20);

        // 初始化分段上传任务
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketname, fileUrl);
        InitiateMultipartUploadResult result = obsClient.initiateMultipartUpload(request);

        final String uploadId = result.getUploadId();
//        System.out.println("\t" + uploadId + "\n");

        // 每段上传5MB
        long partSize = 5 * 1024 * 1024L;
        long fileSize = largeFile.length();

        // 计算需要上传的段数
        long partCount = fileSize % partSize == 0 ? fileSize / partSize : fileSize / partSize + 1;

        final List<PartEtag> partEtags = Collections.synchronizedList(new ArrayList<PartEtag>());

        // 执行并发上传段
        for (int i = 0; i < partCount; i++) {
            // 分段在文件中的起始位置
            final long offset = i * partSize;
            // 分段大小
            final long currPartSize = (i + 1 == partCount) ? fileSize - offset : partSize;
            // 分段号
            final int partNumber = i + 1;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    UploadPartRequest uploadPartRequest = new UploadPartRequest();
                    uploadPartRequest.setBucketName(bucketname);
                    uploadPartRequest.setObjectKey(fileUrl);
                    uploadPartRequest.setUploadId(uploadId);
                    uploadPartRequest.setFile(largeFile);
                    uploadPartRequest.setPartSize(currPartSize);
                    uploadPartRequest.setOffset(offset);
                    uploadPartRequest.setPartNumber(partNumber);

                    UploadPartResult uploadPartResult;
                    try {
                        uploadPartResult = obsClient.uploadPart(uploadPartRequest);
//                        System.out.println("Part#" + partNumber + " done\n");
                        partEtags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
                    } catch (ObsException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // 等待上传完成
        executorService.shutdown();
        while (!executorService.isTerminated()) {
            try {
                executorService.awaitTermination(5, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 合并段
        CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketname, fileUrl, uploadId, partEtags);
        obsClient.completeMultipartUpload(completeMultipartUploadRequest);
        String url = Const.OBS_URL + fileUrl;
        try {
            obsClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return url;
    }


    /**
     * 获取指定文件下载url,并设置有效期
     * @Author baoruizhe
     * @Date 16:13 2020/8/21
     * @Param [bucketname, objectname, expireSeconds]
     * @return java.lang.String
     **/
    public String getSignUrl(String bucketname, String objectname, long expireSeconds) {
        // 创建ObsClient实例
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);
        if (expireSeconds == 0) {
            // URL有效期,默认3600秒
            expireSeconds = 3600L;
        }

        TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
        request.setBucketName(bucketname);
        request.setObjectKey(objectname);

        TemporarySignatureResponse response = obsClient.createTemporarySignature(request);

        System.out.println("Getting object using temporary signature url:");
        System.out.println("\t" + response.getSignedUrl());
        return response.getSignedUrl();
    }



    /**
     * 删除文件
     *
     * @param url
     */
    public void deleteFile(String url) {
        String fileUrl = StringUtils.substringAfterLast(url, "/");
        fileUrl = fileUrl.replaceAll("%2F", "/");
        ObsClient obsClient = new ObsClient(ak, sk, endpoint);
        DeleteObjectResult deleteObjectResult = obsClient.deleteObject(bucketname, fileUrl);
        String objectKey = deleteObjectResult.getObjectKey();
        System.out.println(objectKey);
    }


    /**
     * 获取对象属性
     *
     * @param fileName
     * @return boolean
     * @author kangdong
     * @date 2019/9/18
     */
    public boolean checkObject(String fileName, HuaweiObsInfo huaweiObsInfo) {
        // 创建ObsClient实例
        final ObsClient obsClient = new ObsClient(huaweiObsInfo.getAk(), huaweiObsInfo.getSk(), huaweiObsInfo.getEndpoint());

        try {
            ObjectMetadata metadata = obsClient.getObjectMetadata(huaweiObsInfo.getBucketName(), fileName);
            if (metadata.getContentLength() > 0) {
                return true;
            }
        } catch (ObsException e) {
//            log.error(e.getMessage(), e);
            return false;
        }
        return false;
    }

    /**
     * 获取桶下某个文件夹下所有文件
     *
     * @param
     * @return void
     * @author kangdong
     * @date 2019/9/18
     */
    public void getObjectList() {
//        // 创建ObsClient实例
//        ObsClient obsClient = new ObsClient(ak, sk, endpoint);
//
//        ListObjectsRequest request = new ListObjectsRequest(bucketname);
//        // 设置文件夹对象名"dir/"为前缀
//        request.setPrefix("backupFiles/");
//        request.setMaxKeys(1000);
//
//        ObjectListing result;
//        Set<DeviceInfo> set = null;
//        do {
//            set = new LinkedHashSet<>();
//            result = obsClient.listObjects(request);
//            DeviceInfo deviceInfo = null;
//            for (ObsObject obsObject : result.getObjects()) {
//                deviceInfo = new DeviceInfo();
//                String objectKey = obsObject.getObjectKey();
//                System.out.println("========================objectKey=========================" + objectKey);
//                String deviceId = StringUtils.substringBetween(objectKey, "backup_", ".zip");
//                if (deviceId.contains("_")) {
//                    deviceId = StringUtils.substringBefore(deviceId, "_");
//                }
//                //Pattern pattern = Pattern.compile("[0-9]*");
//                //Matcher isNum = pattern.matcher(deviceId);
//                Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
//                if (pattern.matcher(deviceId).matches() && deviceId.length() < 9) {
//                    DeviceInfo obj = iDeviceinfoService.selectById(Integer.valueOf(deviceId));
//                    if (Objects.isNull(obj)) {
//                        deviceInfo = iDeviceinfoService.getSpecialDeviceInfo(null, null, null, null, null);
//                        deviceInfo.setId(Integer.valueOf(deviceId));
//                        deviceInfo.setBackupFileName(objectKey);
//                        set.add(deviceInfo);
//                    }
//                }
//            }
//            System.out.println("========================insertBatch=========================");
//            iDeviceinfoService.insertBatch(new ArrayList<>(set));
//            request.setMarker(result.getNextMarker());
//        } while (result.isTruncated());
    }




    /**
     * 指定过期时间,获取可以上传对象的url验证地址
     * @Author baoruizhe
     * @Date 16:28 2020/11/18
     * @Param [objectName, expireSeconds]
     * @return java.lang.String
     **/
    public String getUploadSignUrl(String objectName, Long expireSeconds) {
        try {
            // 创建ObsClient实例
            ObsClient obsClient = new ObsClient(ak, sk, endpoint);
            // URL有效期:默认1200秒, 20分钟
            if (expireSeconds == null) {
                expireSeconds = 1200L;
            }

            Map<String, String> headers = new HashMap<String, String>();
            String contentType = "text/plain";
            headers.put("Content-Type", contentType);
            headers.put("Access-Control-Allow-Origin", "*");
            headers.put("Access-Control-Request-Method", "PUT,GET,POST,DELETE,HEAD");

            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.PUT, expireSeconds);
            request.setBucketName(bucketname);
            request.setObjectKey(objectName);
            request.setHeaders(headers);

            TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
//        System.out.println("Creating object using temporary signature url:");
//        System.out.println("\tresponse.getSignedUrl():"  + response.getSignedUrl());
//        for (Map.Entry<String, String> entry : response.getActualSignedRequestHeaders().entrySet()) {
//            System.out.println("entry.getKey():" + entry.getKey());
//            System.out.println("entry.getValue():" + entry.getValue());
//        }
            return response.getSignedUrl();
        } catch (Exception e) {
            log.info(e.getMessage(),e);
            return null;
        }
    }

//    public static void main(String[] args) throws IOException {
//        uploadFileBySignUrl("https://weigou-files.obs.cn-north-4.myhuaweicloud.com:443/yjfk/4effe75c2e56452e955bb12d4c10d5f5?AccessKeyId=YXHWNVDZX553NILA7T0B&Expires=1628170250&Signature=W%2B169JRXiu1Wej1Roxve1j3rJlU%3D");
//    }

    public static void uploadFileBySignUrl(String signedUrl) throws IOException {
        String contentType = "text/plain";
        Request.Builder builder = new Request.Builder();
        builder.header("Content-Type", contentType);
        File file = new File("C:\\Users\\Administrator\\Desktop\\xy测试.png");
        //使用PUT请求上传对象
        Request httpRequest = builder.url(signedUrl).put(RequestBody.create(MediaType.parse(contentType), file)).build();
        OkHttpClient httpClient = new OkHttpClient.Builder().followRedirects(false).retryOnConnectionFailure(false)
                .cache(null).build();

        Call c = httpClient.newCall(httpRequest);
        Response res = c.execute();
        System.out.println("\tStatus:" + res.code());
        if (res.body() != null) {
            System.out.println("\tContent:" + res.body().string() + "\n");
        }
        res.close();
    }


    /**
     * 下载
     * @param ObjectKey
     * @param huaweiObsInfo
     * @return
     */
    public String getDownloadUrl(String ObjectKey, HuaweiObsInfo huaweiObsInfo) {
        // 创建ObsClient实例
        ObsClient obsClient = new ObsClient(huaweiObsInfo.getAk(), huaweiObsInfo.getSk(), huaweiObsInfo.getEndpoint());
        // URL有效期，1800秒(30分钟)
        long expireSeconds = 1800L;
        TemporarySignatureResponse response = null;
        try {
            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
            request.setBucketName(huaweiObsInfo.getBucketName());
            request.setObjectKey(ObjectKey);
            response = obsClient.createTemporarySignature(request);
            return response.getSignedUrl();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


//    public static void main(String[] args) {
//        HuaWeiYunOBSUtil huaWeiYunOBSUtil = new HuaWeiYunOBSUtil();
//        String s = huaWeiYunOBSUtil.getDownloadUrl(
//                "backupFiles/82894ff3b9734030bb0e7d86694722da/7d7cf4abfd994420b191774a7bdef8fa.zip"
//        ,HuaweiObsInfo.WEIGOU_DATA);
//        System.out.println(s);
//        System.out.println(s);
//    }

    public void downloadByUrl(String ObjectKey) throws IOException {
        String endPoint1 = "https://obs.cn-north-4.myhuaweicloud.com";
        String ak1 = "0BMSVRG9JMWA8QKWFOSH";
        String sk1 = "To0zo8GfdVMLd7ESvvadRDC3QS2eD5qmfVQIl0OV";

        // 创建ObsClient实例
        ObsClient obsClient = new ObsClient(ak1, sk1, endPoint1);
        // URL有效期，360秒(6分钟)
        long expireSeconds = 60L;
        TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
        request.setBucketName("weigou-data");
        request.setObjectKey(ObjectKey);
        TemporarySignatureResponse response = obsClient.createTemporarySignature(request);

        System.out.println("Getting object using temporary signature url:");
        System.out.println("\t" + response.getSignedUrl());
        Request.Builder builder = new Request.Builder();
        for (Map.Entry<String, String> entry : response.getActualSignedRequestHeaders().entrySet()) {
            builder.header(entry.getKey(), entry.getValue());
        }
        //使用GET请求下载对象
        Request httpRequest = builder.url(response.getSignedUrl()).get().build();
        OkHttpClient httpClient = new OkHttpClient.Builder().followRedirects(false).retryOnConnectionFailure(false)
                .cache(null).build();
        Call c = httpClient.newCall(httpRequest);
        Response res = c.execute();
        int code = res.code();
        System.out.println("\tStatus:" + code);
        if (200 == code) {
            System.out.println("\tContent:" + res.body().string() + "\n");
            DownloadURLFile.downloadFromUrl(response.getSignedUrl(),"D:\\upload\\");
        }else {
            System.out.println("下载异常!");
        }
//        if (res.body() != null) {
//            System.out.println("\tContent:" + res.body().string() + "\n");
//            InputStream inputStream = res.body().byteStream();
//            byte[] bytes = res.body().bytes();
////            FileUtil.writeToLocal("D:\\upload\\test1.txt",inputStream);
////            FileUtils.copyToFile(inputStream,new File("D:\\upload\\test1.txt"));
//
//        }
    }



    //内网上传
    public  static  String uploadLwFile(String filePath ,String obsPath  , String fileName , Integer timeOut ){
        //内网方式
        String unzipBootImg = "/data/obsutil/run.sh " + filePath + " "+obsPath;
        String command = CommandUtil.execCMD(unzipBootImg
                , null, timeOut);
        log.info(command);
//                    if (command.contains("100%")){
//                    }else {
//                    }
        return  "https://weigou-files.obs.cn-north-4.myhuaweicloud.com/"+obsPath+"/" + fileName;
    }



    //内网下载
    public  static  void downloadLwFile(String obsFilePath ,String filePath  , Integer timeOut ){
        //内网方式
        String unzipBootImg = "/data/obsutil/download.sh " + obsFilePath + " "+filePath;
        String command = CommandUtil.execCMD(unzipBootImg
                , null, timeOut);
//                    if (command.contains("100%")){
//                    }else {
//                    }
        log.info(command);
    }

    //刷新 cdn 缓存
    public  static  void refreshTasks(List<String> obsFilePath ,String type){

//        账号：zyykj888
//密码：zy010847

//        账号：zyykj999
//密码：abcd123156@
        //IAMDomain  IAM用户所属帐号名
        //IAMUser IAM用户名
        //IAMPassword IAM用户密码
        //IAMDomain IAM用户所属帐号名
        String body ="{\"auth\": {\"identity\": {\"methods\": [\"password\"],\"password\": {\"user\": {\"domain\": {\"name\": \"zyykj888\"}," +
                "\"name\": \"zyykj999\",\"password\": \"abcd123156@\"}}},\"scope\": {\"domain\": {\"id\": \"fd027764d1534485ac0b0c106be91fa3\"} }}}";

        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("https://iam.myhuaweicloud.com/v3/auth/tokens");
            httpPost.addHeader("Content-Type", "application/json");
            httpPost.setEntity(new StringEntity(body ,"UTF-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            String SubjectToken = response.getFirstHeader("X-Subject-Token").getValue();
            System.out.println(SubjectToken);


            Map<String , Object> Bodymap = new HashMap<>();
            Map<String , Object> refresh_task = new HashMap<>();
            refresh_task .put("type" ,type );
            refresh_task .put("urls" , obsFilePath);
            Bodymap.put("refresh_task" , refresh_task);
            JSONObject BodymapJson = JSONObject.fromObject(Bodymap);
            httpClient = HttpClients.createDefault();
            httpPost = new HttpPost("https://cdn.myhuaweicloud.com/v1.0/cdn/content/refresh-tasks");
            httpPost.addHeader("Content-Type", "application/json");
            httpPost.addHeader("X-Auth-Token", SubjectToken);
            httpPost.setEntity(new StringEntity(BodymapJson.toString() ,"UTF-8"));
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();

            String responseContent = EntityUtils.toString(entity, "UTF-8");
            System.out.println(responseContent);
            httpClient.close();
            httpPost.clone();
            response.close();



        } catch (Exception e) {
            e.printStackTrace();
        }



    }

    public static void main(String[] args) {
        List<String> obsFilePat = new ArrayList<>();
        obsFilePat.add("https://hsxh5.youju2022.top/rights-h5-hsx/");
        refreshTasks(obsFilePat ,"directory");


//
//        File upfile =  new File("") ;
//        String mp4url = largeUpload(UUID.randomUUID() + "."+filePaths[1]
//                ,"play/"+theaterPlay.getId() ,  upfile);
//        file
//        directory
    }


}
